package com.tbit.uqbike.tergateway.event.impl;

import com.alibaba.fastjson.JSONObject;
import com.tbit.uqbike.TerGatewayMain;
import com.tbit.uqbike.protocol.ABaseHandleObj;
import com.tbit.uqbike.protocol.ATerPkg;
import com.tbit.uqbike.service.db.DbService;
import com.tbit.uqbike.service.redis.RedisService;
import com.tbit.uqbike.tergateway.config.GateXmlConfig;
import com.tbit.uqbike.tergateway.config.TerGatewayConfig;
import com.tbit.uqbike.tergateway.data.TerGatewayData;
import com.tbit.uqbike.tergateway.entity.AConnInfo;
import com.tbit.uqbike.tergateway.entity.ConnInfo;
import com.tbit.uqbike.tergateway.entity.PlatformPointData;
import com.tbit.uqbike.tergateway.entity.SignalInfo;
import com.tbit.uqbike.tergateway.entity.TerTempData;
import com.tbit.uqbike.tergateway.event.ITerEvent;
import com.tbit.uqbike.tergateway.log.LOG;
import com.tbit.uqbike.tergateway.pojo.PlatformPoint;
import com.tbit.uqbike.tergateway.pojo.TerAlarm;
import com.tbit.uqbike.tergateway.pojo.TerAttrEx;
import com.tbit.uqbike.tergateway.pojo.TerBattery;
import com.tbit.uqbike.tergateway.pojo.TerMsg;
import com.tbit.uqbike.tergateway.pojo.TerOnline;
import com.tbit.uqbike.tergateway.pojo.TerOnlineHis;
import com.tbit.uqbike.tergateway.pojo.TerPos;
import com.tbit.uqbike.tergateway.pojo.TerUpdate;
import com.tbit.uqbike.tergateway.wa206pkg.BatteryInfo;
import com.tbit.uqbike.tergateway.wa206pkg.GetFirmware;
import com.tbit.uqbike.tergateway.wa206pkg.PosInfo;
import com.tbit.uqbike.util.ByteUtil;
import com.tbit.uqbike.util.ConstDefine;
import com.tbit.uqbike.util.DateUtil;
import com.tbit.uqbike.util.ErrorCode;
import com.tbit.uqbike.util.StringUtil;
import com.tbit.uqbike.util.TerPubUtil;
import com.tbit.utils.PlatformPointConst;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;

/**
 * Created by MyWin on 2017/5/5.
 */
public class TerEventImpl implements ITerEvent {
    private static Logger logger = LoggerFactory.getLogger(TerEventImpl.class);
    private static Logger filterfile = LoggerFactory.getLogger("filterfile");

    @Override
    public TerTempData TerRecvPkg(String connId, String mno, String protocolName) {
        // 收到终端报文 建立conn和mno的映射关系
        // 只有第一次的时候才建立关系
        TerTempData terTempData = TerGatewayData.getTerTempDataByMno(mno);
        terTempData.protocolName = protocolName;
        // 直接复制
        if (terTempData.updateConnId(connId)) {
            terTempData.updateRouteKey(TerGatewayConfig.routeKey);
            // 连接绑定的时候处理在线状态
            handleTerOnline(mno);
            terTempData.reConnEvent();
            // 推送埋点数据
            TerGatewayData.statDataTask.addStatData(TerGatewayConfig.pointDataStatKey, buildPointItem(mno, connId));
        }
        AConnInfo connInfo = TerGatewayData.GetConnect(connId);
        if (null != connInfo) {
            connInfo.mno = mno;
        }
        terTempData.updateLastPkgDt(new Date());
        return terTempData;
    }

    private String buildPointItem(String mno, String connId) {
        PlatformPointData data = new PlatformPointData();
        data.ident = mno;
        data.datas = new LinkedList<>();

        PlatformPoint pp = new PlatformPoint();
        pp.setDataType(PlatformPointConst.TER_NEW_CONN);
        pp.setIdent(data.ident);
        pp.setDt(new Date());
        pp.setDataValue(connId);
        data.datas.add(pp);

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("msgId", ConstDefine.MQ_MSG_ID_PLATFORM_PP);
        jsonObject.put("feedback", StringUtil.Empty);
        jsonObject.put("data", data);
        return jsonObject.toJSONString();
    }


    /**
     * 处理终端上线事件
     *
     * @param sn
     */
    private void handleTerOnline(String sn) {
        RedisService rs = TerGatewayMain.getRedis();
        // 生成在线对象
        TerOnline online = new TerOnline();
        online.setMno(sn);
        online.setOnline((byte) 1);
        online.setDt(new Date(System.currentTimeMillis()));
        // 获取redis记录，并检测是否需要插入历史记录
        TerOnlineHis offitem = null;
        String hashId = TerGatewayData.getTerHashId(sn);
        String ofStr = rs.get(hashId, TerGatewayData.terOnlineFlag);
        if (!StringUtil.IsNullOrEmpty(ofStr)) {
            offitem = new TerOnlineHis();
            offitem.setMno(sn);
            offitem.setOnline((byte) 0);
            offitem.setDt(new Date(Long.parseLong(ofStr)));
            offitem.setEndDt(online.getDt());

            if (LOG.bOnline) {
                LOG.ONLINE.info(String.format("设备:%s 上线，并插入上次离线时间:%s", sn, ofStr));
            }
        } else {
            if (LOG.bOnline) {
                LOG.ONLINE.info(String.format("设备:%s 上线，不用插入离线时间", sn));
            }
        }
        // 覆盖redis记录
        rs.set(hashId, TerGatewayData.terOnlineFlag, Long.toString(online.getDt().getTime()));
        // 更新最后状态，插入历史数据
        List<TerOnlineHis> items = new LinkedList<>();
        if (null != offitem) {
            items.add(offitem);
            TerGatewayData.insertOnlineItems(items);
        }
        TerGatewayData.updateOnlineItem(online);
    }

    @Override
    public void NewConnectComing(ChannelHandlerContext ctx) {
        ConnInfo info = new ConnInfo(ctx);
        TerGatewayData.AddConnect(info);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        try {
            String connid = ctx.channel().id().toString();
            if (msg instanceof ATerPkg) {
                AConnInfo info = TerGatewayData.GetConnect(connid);
                handleMsg(info, (ATerPkg) msg);
            }
        } catch (Exception e) {
            logger.error("Handle Ter Pkg", e);
        }
    }

    @Override
    public void handleMsg(AConnInfo connInfo, ATerPkg aTerPkg) {
        String mno = connInfo.mno;
        if (!StringUtil.IsNullOrEmpty(mno) && TerGatewayConfig.BopenPkgLog) {
            TerGatewayData.addTerMsg(new TerMsg(mno, new Date(), JSONObject.toJSONString(aTerPkg), ByteUtil.BytesToHexString(aTerPkg.signPkg)));
        }
        try {
            aTerPkg.doBusiness();
        } catch (Exception e) {
            // 所有的业务处理，捕捉一下异常
            logger.error("handleMsg", e);
        }
    }

    @Override
    public boolean interferenceSignalChcek(String sn, SignalInfo signalInfo) {
        // 缓存最近的10个点，如果出现0的基站，并且GSM信号或者GPS信号出现突变（0-9或者9-0）
        //
        TerTempData envir = TerGatewayData.getTerTempDataByMno(sn);
        envir.siList.addLast(signalInfo);
        // 保证缓存长度
        int size = envir.siList.size();
        if (size > TerTempData.SI_MAX_LEN) {
            envir.siList.removeFirst();
            size--;
        }
        // 保证集合数量足够
        if (size > TerTempData.SI_MIN_LEN) {
            int zeroCellCnt = 0;
            int gsmChangeCnt = 0;
            int gpsChangeCnt = 0;
            SignalInfo last = null;
            for (SignalInfo item : envir.siList) {
                if (item.cellId == null || item.cellId.replace("0", "").replace(".","").isEmpty()) {
                    zeroCellCnt++;
                }
                if (last == null) {
                    last = item;
                    break;
                }
                if ((last.gps == 0 || last.gps == 9) && ((last.gps + item.gps) == 9)) {
                    gpsChangeCnt ++;
                }
                if ((last.gsm == 0 || last.gsm == 9) && ((last.gsm + item.gsm) == 9)) {
                    gpsChangeCnt ++;
                }
            }
            // 缓存最近的10个点，如果出现0的基站，并且GSM信号或者GPS信号出现突变（0-9或者9-0）
            if (zeroCellCnt > 0 && (gpsChangeCnt > 0 || gsmChangeCnt > 0)
                    && zeroCellCnt < size) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        TerGatewayData.DelConnect(ctx.channel().id().toString());
        //logger.info(String.format("连接ID:%s(%s) 断开连接", ctx.channel().id(), ctx.channel().remoteAddress()));
    }

    @Override
    public int terRecvNewPos(TerTempData terTempData, TerPos newPos) {
        TerPos terLastPos = terTempData.getLastPos();
        // 先判断时间 是否合法
        Date now = new Date();
        double timeSec = DateUtil.GetTimeSpanSec(now, newPos.getDt());
        if (timeSec > TerGatewayConfig.MaxHisPosSec) {
            return ErrorCode.ErroeTimeOlder;
        }

        /* 关闭过滤算法
        // 对于静态飘逸如果有敏感信息就copy上一个点，不然就过滤掉
        if ((lastPos.getSpeed() == 0 && newPos.getSpeed() == 0) // 2次速度为0
                //|| (newPos.getSpeed() < 10 && dis < 0.1)
                ) // 速度小于10 且距离小于100
        {
            // 如果有里程不过滤 状态变化不过滤
            if (newPos.getMile() != 0 || newPos.getCarStatus() != lastPos.getCarStatus()) {
                newPos.setLon(lastPos.getLon());
                newPos.setLat(lastPos.getLat());
                newPos.setPointType(lastPos.getPointType());
                return ErrorCode.OK;
            }
            else
                return ErrorCode.ErrorFilterStopMove;
        }*/
        // 计算里程
        int signMile = 0;
        if (null != terLastPos) {
            // 获取时间
            double secInv = DateUtil.GetTimeSpanSec(terLastPos.getDt(), newPos.getDt());
            // 单位是米
            double dis = TerPubUtil.calculateDistance(terLastPos.getLon(), terLastPos.getLat(), newPos.getLon(), newPos.getLat()) * 1000;
            // 如果出现非法经纬度，直接替换
            if (newPos.lacId != null && newPos.lacId.startsWith("460") && newPos.isSatellite()) {
                // 56.5616426885,137.2489221627
                // 1.4570113377,69.1110500387
                if (newPos.getLat() < 1.4570113377 || newPos.getLat() > 56.5616426885 || newPos.getLon() < 56.5616426885 || newPos.getLon() > 137.2489221627) {
                    newPos.setLat(terLastPos.getLat());
                    newPos.setLon(terLastPos.getLon());
                }
            }
            // 开始轨迹过滤
            if (GateXmlConfig.bPosFilter && terLastPos.isSatellite() && newPos.isSatellite() && secInv > 0) {
                int iFilterCode = 0;
                if (dis <= GateXmlConfig.stopFilterDis && terLastPos.getSpeed() == 0 && newPos.getSpeed() == 0) {
                    // 小范围飘逸
                    iFilterCode = 1;
                }
                if (dis >= GateXmlConfig.stopFilterMinDis) {
                    if (secInv < GateXmlConfig.stopFilterMinSec) {
                        // 短时间大飘逸
                        iFilterCode = 3;
                    } else if((dis / secInv) / 3.6 >= GateXmlConfig.maxAvgSpeed){
                        // 正常时间大飘逸
                        iFilterCode = 4;
                    }
                }
                if (dis >= GateXmlConfig.cellMaxDis) {
                    // 同基站大范围飘逸
                    if (terLastPos.lacId.length() > 0
                            && Objects.equals(terLastPos.lacId, newPos.lacId)
                            && Objects.equals(terLastPos.cellId, newPos.cellId)) {
                        // 同基站过滤
                        iFilterCode = 2;
                    }
                }
                if (dis >= GateXmlConfig.lacMaxDis) {
                    // 同小区大范围飘逸
                    if (terLastPos.lacId.length() > 0
                            && Objects.equals(terLastPos.lacId, newPos.lacId)) {
                        // 同基站过滤
                        iFilterCode = 5;
                    }
                }
                // 判定一下是否连续过滤
                if (iFilterCode != 0 && terTempData.fr.filterCnt >= 3) {
                    if (terTempData.fr.getAvgDis(newPos.getLon(), newPos.getLat()) < dis) {
                        filterfile.info(String.format("连续过滤相邻位置，修正位置,code:%d,lastpos:%s,newpos:%s", iFilterCode, JSONObject.toJSONString(terLastPos), JSONObject.toJSONString(newPos)));
                        iFilterCode = 0;
                    }
                }

                if (iFilterCode != 0) {
                    terTempData.fr.addFilterPos(newPos.getLon(), newPos.getLat(), newPos.lacId, newPos.cellId);
                    if (GateXmlConfig.filterPosInsertDb) {
                        TerGatewayMain.getDbService().insertFilterDb(newPos);
                    }
                    filterfile.info(String.format("位置过滤,code:%d,lastpos:%s,newpos:%s", iFilterCode, JSONObject.toJSONString(terLastPos), JSONObject.toJSONString(newPos)));
                    newPos.setLon(terLastPos.getLon());
                    newPos.setLat(terLastPos.getLat());
                    dis = 0;
                } else {
                    terTempData.fr.filterCnt = 0;
                }
            }
            // 都是精确定位，且时间正增长
            if (terLastPos.isSatellite() && newPos.isSatellite() && secInv > 0) {
                signMile = (int) dis;
                if (signMile > secInv * 11) {
                    signMile = 0;
                }
            }
        }
        newPos.setMile(signMile);
        if (terLastPos == null || newPos.isNewPos(terLastPos)) {
            // 更新最后状态
            terTempData.updateStatus(newPos.getDt(), newPos.getCarStatus(), newPos.signalStatus);
            // 更新最后位置
            if (TerGatewayConfig.LastPosMustSatellite && newPos.isSatellite()) {
                // 更新内存
                terTempData.updateLastPos(newPos);
            }
        }
        // 插入历史轨迹
        TerGatewayData.addTerHisPos(newPos);
        // 推送给公共平台
        TerGatewayMain.getProducer().sendDataToQueue(TerGatewayConfig.posPushRouteKey, PosInfo.getPosPushMsg(newPos));

        return ErrorCode.OK;
    }

    public static TerAttrEx getTerStopAttr(String mno, boolean bStop) {
        TerAttrEx item = new TerAttrEx();
        item.setMno(mno);
        if (bStop) {
            item.setAttrValue("0");
        } else {
            item.setAttrValue("1");
        }
        item.setAttrDt(new Date());
        item.setAttrName(TerGatewayData.terStopTime);
        return item;
    }

    @Override
    public int terRecvNewBattery(TerTempData terTempData, TerBattery newInfo) {
        int code = ErrorCode.OK;
        // 先判断时间 是否合法
        Date now = new Date();
        double timeSec = DateUtil.GetTimeSpanSec(now, newInfo.getDt());
        if (timeSec > TerGatewayConfig.MaxBatterySec || timeSec < TerGatewayConfig.MixBatterySec) {
            return ErrorCode.ErroeTimeOlder;
        }
        if (code != ErrorCode.OK) {
            logger.info(String.format("由于:[%s]过滤掉电池信息:[%s]", ErrorCode.ErrorString(ErrorCode.ErroeTimeOlder), newInfo.toString()));
            return code;
        }
        // 更新电压
        terTempData.updateVol(newInfo.getDt(), newInfo.getBatteryEU());
        // 进行处理
        TerBattery terBattery = terTempData.getLastBattery();
        if (terBattery == null) {
            // 立即插入最后位置
            DbService dbService = TerGatewayMain.getDbService();
            dbService.insertLastTerBattery(newInfo);
        }
        // 更新有效值
        terTempData.updateLastBattery(newInfo);
        // 获取克隆对象
        TerBattery batteryObj = terTempData.getCloneLastBattery();
        // 推送给公共平台
        TerGatewayMain.getProducer().sendDataToQueue(TerGatewayConfig.batteryPushRouteKey, BatteryInfo.getBatterPushMsg(batteryObj));
        return code;
    }

    @Override
    public int terRecvNewAlarm(TerAlarm newInfo) {
        // 先判断时间 是否合法
        Date now = new Date();
        double timeSec = DateUtil.GetTimeSpanSec(now, newInfo.getDt());
        if (timeSec > TerGatewayConfig.MaxAlarmSec) {
            return ErrorCode.ErroeTimeOlder;
        }
        return ErrorCode.OK;
    }

    @Override
    public void handleBaseHandleObjs(List<ABaseHandleObj> aBaseHandleObjList) {
        for (ABaseHandleObj aBaseHandleObj : aBaseHandleObjList) {
            handleBaseHandleObj(aBaseHandleObj);
        }
    }

    @Override
    public void handleBaseHandleObj(ABaseHandleObj aBaseHandleObj) {
        aBaseHandleObj.doBusiness();
    }

    @Override
    public void terUpdateCompete(GetFirmware getFirmware) {
        DbService dbService = TerGatewayMain.getDbService();
        // 插入升级成功记录
        TerUpdate terUpdate = new TerUpdate();
        terUpdate.setDt(new Date());
        terUpdate.setMachineno(getFirmware.mno);
        terUpdate.setCustomercode(getFirmware.customerCode);
        terUpdate.setHardwaremodel(getFirmware.hardwareModel);
        terUpdate.setVersion(getFirmware.version);
        terUpdate.setFirmwaretype(getFirmware.firmwareType);
        dbService.insertTerUpdate(terUpdate);
        // 删除升级配置
        dbService.deleteByMnoType(getFirmware.mno, ConstDefine.TER_CONFIG_TER_UPDATE);
        // 清空升级缓存
        TerGatewayData.setTersoftwareKeyEmpty(getFirmware.mno);
    }




}
